package com.ymt.bpm.engine.bpmn;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.ymt.bpm.dao.MDao;
import com.ymt.bpm.dao.Mapper;
import com.ymt.bpm.engine.listener.engine.exception.EngineException;
import com.ymt.bpm.model.PDataM;
import com.ymt.bpm.model.PTaskDone;
import com.ymt.bpm.model.PTaskTodo;
import com.ymt.bpm.util.DateUtil;
import com.ymt.bpm.util.DbDialectUtil;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.*;

/**
 * Created by Johnny on 2017/4/22.
 */
public class ProcessUtil {

    private static Logger logger = LoggerFactory.getLogger(ProcessUtil.class);

    public static JSONObject generateProcessVarialbes(JSONObject conf, JSONObject inputVariables) {
        //com.alibaba.fastjson.JSONObject processVar = new com.alibaba.fastjson.JSONObject();
        JSONObject variables = new JSONObject();
        JSONObject inputVars = null;
        if (null==inputVariables) {
            inputVars = new JSONObject();
        } else {
            inputVars = inputVariables;
        }
        JSONObject pvs = (JSONObject) JSONPath.eval(conf, "$.processSettings.variables");
        if (pvs!=null) {
            for (Map.Entry<String, Object> entry : pvs.entrySet()) {
                JSONObject pv = (JSONObject) entry.getValue();
                String pvType = pv.getString("type");
                boolean isValueInInput = false;	//输入值存在
                if ("1".equals(pv.getString("allowin"))) {	//如果有输入的值
                    Object rawv = inputVars.get(entry.getKey());
                    if (rawv!=null) {//有输入值
                        isValueInInput = true;
                    }
                    if ("string".equalsIgnoreCase(pvType) || "date".equalsIgnoreCase(pvType)) {
                        pv.put("value", rawv);
                    } else if ("json".equalsIgnoreCase(pvType)) {
                        pv.put("value", rawv);
                    } else if ("boolean".equalsIgnoreCase(pvType)) {
                        if (null==rawv || rawv.toString().length()==0) {
                            pv.put("value", false);
                        } else {
                            pv.put("value", Boolean.parseBoolean(rawv.toString()));
                        }
                    } else if ("int".equalsIgnoreCase(pvType)) {
                        if (null==rawv || rawv.toString().length()==0) {
                            pv.put("value", null);
                        } else {
                            pv.put("value", Integer.parseInt(rawv.toString()));
                        }
                    } else if ("number".equalsIgnoreCase(pvType)) {
                        if (null==rawv || rawv.toString().length()==0) {
                            pv.put("value", null);
                        } else {
                            pv.put("value", new BigDecimal(rawv.toString()));
                        }
                    }
                }
                //当value为空时，判断是否有默认值
                if((!isValueInInput || pv.get("value")==null) && pv.containsKey("default")) {
                    if ("string".equalsIgnoreCase(pvType) || "date".equalsIgnoreCase(pvType)) {
                        pv.put("value", pv.getString("default"));
                    } else if ("json".equalsIgnoreCase(pvType)) {
                        pv.put("value", pv.get("default"));
                    } else if ("boolean".equalsIgnoreCase(pvType)) {
                        if (!isValueInInput) {	//无输入时取默认值
                            Object rawv = pv.get("default");
                            if (null==rawv || rawv.toString().length()==0) {
                                pv.put("value", false);
                            } else {
                                pv.put("value", Boolean.parseBoolean(rawv.toString()));
                            }
                        }
                    } else if ("int".equalsIgnoreCase(pvType)) {
                        Object rawv = pv.get("default");
                        if (null==rawv || rawv.toString().length()==0) {
                            pv.put("value", null);
                        } else {
                            pv.put("value", Integer.parseInt(rawv.toString()));
                        }
                    } else if ("number".equalsIgnoreCase(pvType)) {
                        Object rawv = pv.get("default");
                        if (null==rawv || rawv.toString().length()==0) {
                            pv.put("value", null);
                        } else {
                            pv.put("value", new BigDecimal(rawv.toString()));
                        }
                    }
                }

                pv.remove("allowin");
                pv.remove("allowout");
                pv.remove("default");
                variables.put(entry.getKey(), pv);
            }
        }
        //processVar.put("variables", variables);
        return variables;
    }

    /**
     * transform variables like {a:{value:1,type:string}} to {a:1}
     * @param variables
     * @return
     */
    public static JSONObject toFlatVariables(JSONObject variables) {
        if (variables==null || variables.isEmpty()) {
            return variables;
        }
        JSONObject rtn = new JSONObject();
        for (String key : variables.keySet()) {
            JSONObject obj = variables.getJSONObject(key);
            rtn.put(key, obj.get("value"));
        }
        return  rtn;
    }

    //预置属性的映射
    public static Map<String, Object> parsePredefinedSysVars(Map<String, Object> inputVars) {
        Map<String, Object> newVars = new HashMap<String, Object>();
        if (inputVars==null) return newVars;
        String[] predefinedSysVars = new String[]{
                "_invokedByServiceNewPi" //通过系统任务发起，系统任务所在流程piEid+"-"+activityId
        };
        for (String psv : predefinedSysVars) {
            if (inputVars.containsKey(psv)) {
                newVars.put(psv, inputVars.get(psv));
            }
        }
        return newVars;
    }

    /**
     * 根据流程配置和流程变量更新业务数据
     *
     *            版本ID
     * @param activityId
     *            环节ID
     * @param conf
     *            流程配置信息bpmnConfig
     * @param processVar
     *            流程变量，格式类似 { "variables" : { "pv1" : { "desc" : "变量描述", "type" : "变量类型string,boolean,int,number,date,json", "value" : <值> }, "pv2" : { "desc" : "变量描述", "type" :
     *            "变量类型string,boolean,int,number,date,json", "value" : <值, 如果date型使用yyyy-MM-dd hh24:mm:ss格式的string表示> } }, "gatewayVar" : { "SequenceFlow_1qzfzz7" : "true",
     *            //此处使用string "SequenceFlow_2ekfee8" : "false" //此处使用string } }
     * @return
     * @throws Exception
     */
    public static JSONObject mappingProcessVarToBizVar(
            // String bpdId,
            // int versionid,
            String activityId, JSONObject conf, JSONObject processVar) {

        // 获取流程配置信息
		/*
		 * if (null == conf) { conf = bpdSvc.getBpdConfigOfVersion(bpdId, versionid); }
		 */

        // 获取流程变量配置信息 pvConf
        JSONObject pvConf = (JSONObject) JSONPath.eval(conf, "$.processSettings.variables");

        // 获取输入映射配置信息 inputConf
        JSONObject mappingConf = (JSONObject) JSONPath.eval(conf, "$." + activityId + ".dataMapping.input");

        if (null != mappingConf && null == pvConf) {
            // 流程变量配置丢失
            // throw new Exception( "MissingConfig::processSettings.variables");
            return null;
        } else if (null != mappingConf && null != pvConf) {// 需要做数据映射的情况
            return generateBizVarTree(mappingConf, pvConf, processVar);
        }
        return null;
    }

    private static JSONObject generateBizVarTree(JSONObject mappingConf, JSONObject pvConf,
                                                 JSONObject processVar) {
        JSONObject rtn = new JSONObject();
		/*
		 * ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("javascript"); try { engine.put("mappingConf", mappingConf);
		 * engine.put("pvConf", pvConf); String rs = (String)engine.eval("var a=3; var b=4;print (a+b);"); } catch (ScriptException e) { e.printStackTrace(); }
		 */
        // 遍历映射关系，生成业务环节的输入数据
        for (Map.Entry<String, Object> entry : mappingConf.entrySet()) {
            String[] ar = entry.getKey().split("\\|");	// 映射的层级关系
            String pvName = (String) entry.getValue();
            if (ar.length > 0) {
                JSONObject pointer = rtn; // 指针，指向当前操作的JSON层级
                for (int j = 0; j < ar.length; j++) {
                    if (j < ar.length - 1) {// 为非叶子节点层级结构
                        if (null == pointer.getJSONObject(ar[j])) {
                            pointer.put(ar[j], new JSONObject());
                        }
                        if (null == pointer.getJSONObject(ar[j]).getJSONObject("children")) {
                            pointer.getJSONObject(ar[j]).put("children", new JSONObject());
                        }
                        pointer = pointer.getJSONObject(ar[j]).getJSONObject("children");
                    } else {// 为叶子节点层级
                        JSONObject val = new JSONObject();
                        // 变量类型
                        if (logger.isDebugEnabled()) {
                            logger.debug("==========" + pvConf);
                            logger.debug(ar[j] + "==========" + pvConf.getJSONObject(pvName));
                        }

                        String pvType = pvConf.getJSONObject(pvName).getString("type");
                        val.put("type", pvType);
                        // 变量值
                        Object rawValue = JSONPath.eval(processVar, "$.variables." + pvName + ".value");
                        if (logger.isDebugEnabled()) {
                            logger.debug(pvName + ">>" + ar[j] + "===" + rawValue);
                        }
                        // 根据不同类型set不同的值
                        if (null == rawValue) {
                            val.put("value", null);
                        } else {
                            if ("string".equalsIgnoreCase(pvType)) {
                                val.put("value", String.valueOf(rawValue));
                            } else if ("int".equalsIgnoreCase(pvType)) {
                                val.put("value", Integer.parseInt(rawValue.toString()));
                            } else if ("number".equalsIgnoreCase(pvType)) {
                                val.put("value", new BigDecimal(rawValue.toString()));
                            } else if ("date".equalsIgnoreCase(pvType)) {
                                val.put("value", String.valueOf(rawValue));
                            } else if ("boolean".equalsIgnoreCase(pvType)) {
                                val.put("value", Boolean.valueOf(rawValue.toString()));
                            } else if ("json".equalsIgnoreCase(pvType)) {
                                val.put("value", rawValue);
                            }
                        }
                        pointer.put(ar[j], val);
                    }
                }
            }
        }
        return rtn;
    }

    /**
     * 根据流程配置和业务数据更新流程变量
     *
     *            版本ID
     * @param activityId
     *            环节ID
     * @param conf
     *            流程配置信息bpmnConfig
     * @param processVar
     *            流程变量，格式类似 { "variables" : { "pv1" : { "desc" : "变量描述", "type" : "变量类型string,boolean,int,number,date,json", "value" : <值> }, "pv2" : { "desc" : "变量描述", "type" :
     *            "变量类型string,boolean,int,number,date,json", "value" : <值, 如果date型使用yyyy-MM-dd hh24:mm:ss格式的string表示> } }, "gatewayVar" : { "SequenceFlow_1qzfzz7" : "true",
     *            //此处使用string "SequenceFlow_2ekfee8" : "false" //此处使用string } }
     * @param bizOutput
     *            环节的业务输出数据，不能为空
     * @return
     * @throws Exception
     */
    public static void mappingBizVarToProcessVar(
            String activityId,
            JSONObject conf,
            JSONObject processVar,
            JSONObject bizOutput,
            boolean complexOutput) {
		/*
		 * //获取流程配置信息 if (null == conf) { conf = bpdSvc.getBpdConfigOfVersion(bpdId, versionid); }
		 */
		if (bizOutput==null) {
		    return;
        }

        // 获取流程变量配置信息 pvConf
        JSONObject pvConf = (JSONObject) JSONPath.eval(conf, "$.processSettings.variables");

        // 获取输入映射配置信息 inputConf
        JSONObject mappingConf = (JSONObject) JSONPath.eval(conf, "$." + activityId + ".dataMapping.output");

        if (null != mappingConf && null == pvConf) {
            // 流程变量配置丢失
            throw new RuntimeException("MissingConfig::processSettings.variables");
        } else if (null != mappingConf && null != pvConf) {// 需要做数据映射的情况
            // 遍历所有映射
            for (Map.Entry<String, Object> entry : mappingConf.entrySet()) {
                // 变量值
                Object rawValue = null;
                if (complexOutput) {
                    rawValue = JSONPath.eval(bizOutput, "$." + entry.getKey().replace("|", ".children.") + ".value");
                } else {
                    String[] keys = entry.getKey().split("\\|");
                    rawValue = bizOutput.get(keys[keys.length-1]);
                }
                // 变量名称
                String pv = (String) entry.getValue();
                // 变量类型
                String pvType = pvConf.getJSONObject(pv).getString("type");
                // 变量描述
                String pvDesc = pvConf.getJSONObject(pv).getString("desc");
                JSONObject val = new JSONObject();
                val.put("type", pvType);
                val.put("desc", pvDesc);
                // 根据不同的值设置不同的变量值
                if (rawValue!=null) {
                    if ("string".equalsIgnoreCase(pvType)) {
                        val.put("value", String.valueOf(rawValue));
                    } else if ("int".equalsIgnoreCase(pvType)) {
                        val.put("value", Integer.parseInt(rawValue.toString()));
                    } else if ("number".equalsIgnoreCase(pvType)) {
                        val.put("value", new BigDecimal(rawValue.toString()));
                    } else if ("date".equalsIgnoreCase(pvType)) {
                        val.put("value", String.valueOf(rawValue));
                    } else if ("boolean".equalsIgnoreCase(pvType)) {
                        val.put("value", Boolean.valueOf(rawValue.toString()));
                    } else if ("json".equalsIgnoreCase(pvType)) {
                        val.put("value", rawValue);
                    }
                } else {
                    val.put("value", "");
                }

                // 放入流程变量中
                processVar.getJSONObject("variables").put(pv, val);
            }
        }
        // 其他情况不处理
    }

    public static void mappingBizVarToProcessVar(
            String activityId, JSONObject conf, JSONObject processVar, JSONObject bizOutput) {
        mappingBizVarToProcessVar(activityId, conf, processVar, bizOutput, true);
    }

    /**
     * @MethodName: updateBODataByTaskConfigAndProcessVar
     * @Description: 方法说明:根据环节输入更新BO表
     * @param input 任务环节配置
     * @param variables 流程变量
     * @param piEid 流程实例id
     * 流程变量，格式类似 { "variables" : { "pv1" : { "desc" : "变量描述", "type" : "变量类型string,boolean,int,number,date,json", "value" : <值> }, "pv2" : { "desc" : "变量描述", "type" :
     *            "变量类型string,boolean,int,number,date,json", "value" : <值, 如果date型使用yyyy-MM-dd hh24:mm:ss格式的string表示> } }, "gatewayVar" : { "SequenceFlow_1qzfzz7" : "true",
     *            //此处使用string "SequenceFlow_2ekfee8" : "false" //此处使用string } }
     */
    public static void updateBODataByTaskConfigAndProcessVar(String tenantId,
                                                             boolean jsonDataEnabled,
                                                             String dialect,
                                                             MDao dao,
                                                             JSONObject input,
                                                       JSONObject variables,
                                                       String piEid){
        if (jsonDataEnabled) {
            Iterator<Map.Entry<String, Object>> it = input.entrySet().iterator();
            Map<String, Map<String, Object>> updators = new HashMap<String, Map<String, Object>>();
            while(it.hasNext()) {
                Map.Entry<String, Object> entry = it.next();
                String key = entry.getKey();
                int idx = key.indexOf("|");
                String model = key.substring(0, idx);
                String column = key.substring(idx+1);
                //流程变量
                String pv = entry.getValue().toString();
                JSONObject pvobj = variables.getJSONObject(pv);
                if (!updators.containsKey(model)) {
                    updators.put(model, new HashMap<String, Object>());
                }
                Map<String, Object> colmap = updators.get(model);
                String type = pvobj.getString("type");
                switch(type){
                    case "string":
                        colmap.put(column, pvobj.get("value"));
                        break;
                    case "boolean":
                        colmap.put(column, pvobj.get("value"));
                        break;
                    case "int":
                        colmap.put(column, pvobj.get("value"));
                        break;
                    case "number":
                        colmap.put(column, pvobj.get("value"));
                        break;
                    case "date":
                        colmap.put(column, pvobj.get("value"));
                        break;
                    case "json":
                        colmap.put(column, pvobj.get("value"));
                        break;
                    default:
                        break;
                }
            }
            Iterator<Map.Entry<String, Map<String, Object>>> it1 = updators.entrySet().iterator();
            while(it1.hasNext()){
                Map.Entry<String, Map<String, Object>> entry = it1.next();
                String model = entry.getKey();
                PDataM dm = new PDataM();
                if (tenantId!=null && StringUtils.isNumeric(tenantId)) {
                    dm.setTenantId(Integer.parseInt(tenantId));
                }
                dm.setPiEid(piEid);
                dm.setModel(model);
                dm = dao.selectOne(Mapper.PDataMMapper, "selectByPrimaryKey", dm);
                JSONObject bizDataJson = JSONObject.parseObject(dm.getBizData());
                bizDataJson.putAll(entry.getValue());
                dm.setBizData(bizDataJson.toJSONString());
                dao.update(Mapper.PDataMMapper, "updateByPrimaryKeySelective", dm);
            }
        } else {
            do{
                String flag = "";//用来标识操作的是同一个表
                StringBuffer sql = new StringBuffer("update ");
                Iterator<Map.Entry<String, Object>> it = input.entrySet().iterator();
                while(it.hasNext()){
                    Map.Entry<String, Object> entry = it.next();
                    String key = entry.getKey();
                    String table = key.substring(0, key.indexOf("|"));
                    String column = key.substring(key.indexOf("|")+1);
                    //流程变量名称
                    String val = entry.getValue().toString();
                    com.alibaba.fastjson.JSONObject valInfo = variables.getJSONObject(val);
                    String type = valInfo.getString("type");

                    if(!table.equals(flag) && "".equals(flag)){//更新特定的一张表，并且第一次进入循环
                        flag = table;
                        sql.append(table);
                        sql.append(tenantId!=null ? "_"+tenantId : "");
                        sql.append(" set ");
                        switch(type){
                            case "string":
                                sql.append(column+" = '"+valInfo.getString("value")+"'");
                                break;
                            case "boolean":
                                sql.append(","+column+" = '"+valInfo.getString("value")+"'");
                                break;
                            case "int":
                                sql.append(column+" = '"+valInfo.getIntValue("value")+"'");
                                break;
                            case "number":
                                sql.append(column+" = '"+valInfo.getBigDecimal("value")+"'");
                                break;
                            case "date":
                                String dateStr = valInfo.getString("value");
                                if (dateStr!=null && dateStr.length()>0) {
                                    sql.append(column+" = '"+ DbDialectUtil.toDateFunc(dialect, dateStr)+"'");
                                }
                                break;
                            case "json":
                                if (valInfo.get("value")!=null) {
                                    JSON json = (JSON)valInfo.get("value"); //JSONObject or JSONArray
                                    sql.append(column+" = '"+json.toString()+"'");
                                }
                                break;
                            default: break;
                        }
                        //从JSON中移除已选对象
                        it.remove();
                        continue;
                    }
                    if(table.equals(flag)){//是同一张表就继续
                        switch(type){
                            case "string":
                                sql.append(","+column+" = '"+valInfo.getString("value")+"'");
                                break;
                            case "boolean":
                                sql.append(","+column+" = '"+valInfo.getString("value")+"'");
                                break;
                            case "int":
                                sql.append(","+column+" = '"+valInfo.getIntValue("value")+"'");
                                break;
                            case "number":
                                sql.append(","+column+" = '"+valInfo.getBigDecimal("value")+"'");
                                break;
                            case "date":
                                String dateStr = valInfo.getString("value");
                                if (dateStr!=null && dateStr.length()>0) {
                                    sql.append(column+" = '"+ DbDialectUtil.toDateFunc(dialect, dateStr)+"'");
                                }
                                break;
                            case "json":
                                if (valInfo.get("value")!=null) {
                                    JSON json = (JSON)valInfo.get("value"); //JSONObject or JSONArray
                                    sql.append(column+" = '"+json.toString()+"'");
                                }
                                break;
                            default: break;
                        }
                        //从JSON中移除已选对象
                        it.remove();

                    }else{//不是同一张表跳过本次循环
                        continue;
                    }
                }
                //where clause
                sql.append(" where ts_id = '"+piEid+"'");
                logger.debug("update botable sql:"+sql.toString());
                //查询bo table 如果没有就插入，如果有就更新
                Map<String, String> sqlMap = new HashMap<String, String>();
                sqlMap.put("sql", "select ts_id from "+(flag + (tenantId!=null ? "_"+tenantId : ""))+" where ts_id = '"+piEid+"'");
                Map<String,?> ret = dao.selectOne(Mapper.CustomSQLMapper, "selectOne", sqlMap);
                if(null == ret){
                    // 如果BO数据未生成，暂时不进行更新
                }else{
                    Map<String, String> sqlMapUpdate = new HashMap<String, String>();
                    sqlMap.put("sql", sql.toString());
                    int rs = dao.update(Mapper.CustomSQLMapper, "update", sqlMapUpdate);
                    logger.debug("updated bo size ="+rs);
                }

            }while(!input.isEmpty());//input is not null go on loop
        }
    }

    public static void calculateGatewayVar(
            // String bpdId,
            // int versionid,
            String activityId, com.alibaba.fastjson.JSONObject conf, com.alibaba.fastjson.JSONObject processVar) {

        // 初始化gatewayVar，如果不存在则设置
        if (processVar.getJSONObject("gatewayVar") == null) {
            processVar.put("gatewayVar", new com.alibaba.fastjson.JSONObject());
        }

        // 获取流程配置信息
		/*
		 * if (null == conf) { conf = bpdSvc.getBpdConfigOfVersion(bpdId); }
		 */

        // 获取流程变量配置信息 pvConf
        com.alibaba.fastjson.JSONObject pvConf = (com.alibaba.fastjson.JSONObject) JSONPath.eval(conf, "$.processSettings.variables");

        // 获取输入映射配置信息 inputConf
        com.alibaba.fastjson.JSONObject tcs = (com.alibaba.fastjson.JSONObject) JSONPath.eval(conf, "$." + activityId + ".route.transitionConditions");

        if (null != tcs && !tcs.isEmpty()) { // 有路径条件设置
            for (Map.Entry<String, Object> entry : tcs.entrySet()) {
                String path = entry.getKey();
                com.alibaba.fastjson.JSONArray conds = (com.alibaba.fastjson.JSONArray) entry.getValue();
                if (null != conds && conds.size() > 0) { // 路径上有一到多条条件
                    boolean result = true; // 结果，如果一条不满足则为不满足
                    for (int i = 0; i < conds.size(); i++) {
                        com.alibaba.fastjson.JSONObject cond = conds.getJSONObject(i);
                        String pv = cond.getString("varname");
                        String pvType = pvConf.getJSONObject(pv).getString("type");
                        String operator = cond.getString("operator");
                        Object rawValue = cond.get("value");
                        Object pvValue = processVar.getJSONObject("variables").getJSONObject(pv).get("value");
                        // 根据不同类型判断条件
                        if ("string".equalsIgnoreCase(pvType)) {
                            if ("equal".equalsIgnoreCase(operator)) {
                                result = (null == rawValue && null == pvValue)
                                        || (null != rawValue && null != pvValue && String.valueOf(rawValue).equalsIgnoreCase(String.valueOf(pvValue)));
                            } else if ("notequal".equalsIgnoreCase(operator)) {
                                result = (null == rawValue && null != pvValue) || (null != rawValue && null == pvValue)
                                        || (null != rawValue && null != pvValue && !String.valueOf(rawValue).equalsIgnoreCase(String.valueOf(pvValue)));
                            } else if ("contains".equalsIgnoreCase(operator)) {
                                result = null != rawValue && null != pvValue && String.valueOf(pvValue).indexOf(String.valueOf(rawValue)) >= 0;
                            } else if ("notcontains".equalsIgnoreCase(operator)) {
                                result = (null == rawValue && null != pvValue) || (null != rawValue && null == pvValue) || null != rawValue && null != pvValue
                                        && String.valueOf(pvValue).indexOf(String.valueOf(rawValue)) < 0;
                            }
                        } else if ("int".equalsIgnoreCase(pvType) || "number".equalsIgnoreCase(pvType)) {
                            BigDecimal pvv = new BigDecimal(pvValue.toString());
                            BigDecimal pvc = new BigDecimal(rawValue.toString());
                            if ("equal".equalsIgnoreCase(operator)) {
                                result = pvv.compareTo(pvc) == 0;
                            } else if ("notequal".equalsIgnoreCase(operator)) {
                                result = pvv.compareTo(pvc) != 0;
                            } else if ("greaterthan".equalsIgnoreCase(operator)) {
                                result = pvv.compareTo(pvc) > 0;
                            } else if ("lessthan".equalsIgnoreCase(operator)) {
                                result = pvv.compareTo(pvc) < 0;
                            } else if ("greaterequal".equalsIgnoreCase(operator)) {
                                result = pvv.compareTo(pvc) >= 0;
                            } else if ("lessequal".equalsIgnoreCase(operator)) {
                                result = pvv.compareTo(pvc) <= 0;
                            }
                        } else if ("date".equalsIgnoreCase(pvType)) {
                            if ("equal".equalsIgnoreCase(operator)) {
                                result = (null == rawValue && null == pvValue)
                                        || (null != rawValue && null != pvValue && String.valueOf(rawValue).equalsIgnoreCase(String.valueOf(pvValue)));
                            } else if ("notequal".equalsIgnoreCase(operator)) {
                                result = (null == rawValue && null != pvValue) || (null != rawValue && null == pvValue)
                                        || (null != rawValue && null != pvValue && !String.valueOf(rawValue).equalsIgnoreCase(String.valueOf(pvValue)));
                            } else if ("greaterthan".equalsIgnoreCase(operator)) {
                                result = (null == rawValue && null != pvValue)
                                        || (null != rawValue && null != pvValue && String.valueOf(pvValue).compareTo(String.valueOf(rawValue)) > 0);
                            } else if ("lessthan".equalsIgnoreCase(operator)) {
                                result = (null != rawValue && null == pvValue)
                                        || (null != rawValue && null != pvValue && String.valueOf(pvValue).compareTo(String.valueOf(rawValue)) < 0);
                            } else if ("greaterequal".equalsIgnoreCase(operator)) {
                                result = (null == rawValue && null != pvValue)
                                        || (null != rawValue && null != pvValue && String.valueOf(pvValue).compareTo(String.valueOf(rawValue)) >= 0);
                            } else if ("lessequal".equalsIgnoreCase(operator)) {
                                result = (null != rawValue && null == pvValue)
                                        || (null != rawValue && null != pvValue && String.valueOf(pvValue).compareTo(String.valueOf(rawValue)) <= 0);
                            }
                        } else if ("boolean".equalsIgnoreCase(pvType)) {
                            if (null == pvValue) { // 默认值
                                pvValue = "false";
                            }
                            result = Boolean.valueOf(rawValue.toString()).equals(Boolean.valueOf(pvValue.toString()));
                        } else if ("json".equalsIgnoreCase(pvType)) {
                            if ("in".equalsIgnoreCase(operator)) {
                                result = null != rawValue && null != pvValue && com.alibaba.fastjson.JSONObject.toJSONString(pvValue).indexOf(String.valueOf(rawValue)) >= 0;
                            } else if ("notin".equalsIgnoreCase(operator)) {
                                result = (null == rawValue && null != pvValue) || (null != rawValue && null == pvValue)
                                        || (null != rawValue && null != pvValue && com.alibaba.fastjson.JSONObject.toJSONString(pvValue).indexOf(String.valueOf(rawValue)) < 0);
                            }
                        }
                        if (!result) {
                            break; // stop on false
                        }
                    }
                    if (result) {
                        processVar.getJSONObject("gatewayVar").put(path, "true");
                    } else {
                        processVar.getJSONObject("gatewayVar").put(path, "false");
                    }
                }
            }
        }
        logger.debug("calculateGatewayVar returns processVar=" + processVar);
    }

    public static void skipTo(DelegateExecution exe, String skipTo){

        String destActivity = null;
        String newPath = null;
        if(skipTo.indexOf("|") >= 0){
            destActivity = skipTo.substring(0, skipTo.indexOf("|", 0));
            newPath = skipTo.substring(skipTo.indexOf("|", 0)+1, skipTo.length());
        }else{
            destActivity = skipTo;
        }
        //准备为子流程传递新的跳转路径
        exe.setVariable("skipTo", newPath);
        // 取得流程定义
        ProcessDefinitionEntity defination = (ProcessDefinitionEntity) ((RepositoryServiceImpl)exe.getEngineServices().getRepositoryService()).getDeployedProcessDefinition(exe.getProcessDefinitionId());
        if (defination == null) {
            logger.error("processDefination not found!");
            throw new RuntimeException(new EngineException("", "processDefination not found! while doing skipTo."));
        } else {
            // 取得上一步活动
//			ActivityImpl currentActiviti = ((ProcessDefinitionImpl) defination)
//					.findActivity(exe.getCurrentActivityId() != null ? exe.getCurrentActivityId():startId);
            ExecutionEntity ex = (ExecutionEntity)exe;
            final ActivityImpl currentActiviti = ex.getStartingExecution().getInitial();
            // 清除当前活动的出口
            List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();
            List<PvmTransition> pvmTransitionList = currentActiviti.getOutgoingTransitions();
            for (PvmTransition pvmTransition : pvmTransitionList) {
                oriPvmTransitionList.add(pvmTransition);
            }
            pvmTransitionList.clear();
            // 建立新出口
            List<TransitionImpl> newTransitions = new ArrayList<TransitionImpl>();
            ActivityImpl nextActivityImpl = ((ProcessDefinitionImpl) defination).findActivity(destActivity);
            TransitionImpl newTransition = currentActiviti.createOutgoingTransition();
            newTransition.setDestination(nextActivityImpl);
            newTransitions.add(newTransition);
            //TODO 恢复出口？
        }
    }

    public static Date getDueTime(String timelineUnit, String duration) {
        Date expireDaters = null;
        if(null != timelineUnit){
            Calendar expireDate = Calendar.getInstance(new SimpleTimeZone(0, "GMT"));
            if(timelineUnit.equals("day")){
                expireDate.add(Calendar.DAY_OF_MONTH, Integer.parseInt(duration));
            }else if(timelineUnit.equals("hour")){
                expireDate.add(Calendar.HOUR_OF_DAY, Integer.parseInt(duration));
            }else if(timelineUnit.equals("min")){
                expireDate.add(Calendar.MINUTE, Integer.parseInt(duration));
            }
            expireDaters = DateUtil.getGMTDate(expireDate.getTime());
        }
        return expireDaters;
    }

    public static Date getPiDueTimeFromNow(JSONObject bpmnConfig) {
        Object timelineUnit = JSONPath.eval(bpmnConfig, "$.Collaboration_1.timelineUnit");
        if(null != timelineUnit){
            Calendar dueTime = Calendar.getInstance();
            Object duration = JSONPath.eval(bpmnConfig, "$.Collaboration_1.duration");
            if(timelineUnit.equals("day")){
                dueTime.add(Calendar.DAY_OF_MONTH, Integer.parseInt(duration.toString()));
            }else if(timelineUnit.equals("hour")){
                dueTime.add(Calendar.HOUR_OF_DAY, Integer.parseInt(duration.toString()));
            }else if(timelineUnit.equals("min")){
                dueTime.add(Calendar.MINUTE, Integer.parseInt(duration.toString()));
            }
            return DateUtil.getGMTDate(dueTime.getTime());
        }
        return null;
    }

    public static boolean isCompleteEngineTask(MDao dao, PTaskTodo todo) {
        boolean completeEngineTask = false;
        switch (todo.gettType()) {
            case PTaskTodo.TYPE_NORMAL:
                dao.delete(Mapper.PTaskTodoMapper, "deleteSameTypeOtherTodosOnActivity", todo);
                break;
            case PTaskTodo.TYPE_COMPETE:
                dao.delete(Mapper.PTaskTodoMapper, "deleteSameTypeOtherTodosOnActivity", todo);
                break;
            case PTaskTodo.TYPE_INVOLVED_BEFORE:
                int countBf = dao.selectOne(Mapper.PTaskTodoMapper, "countSameTypeOtherTasks", todo);
                if (countBf==0) {   //更新加签来源隐藏任务为非隐藏
                    /*PTaskTodo t1 = new PTaskTodo();
                    if (todo.getTenantId()!=null && todo.getTenantId()>0) {
                        t1.setTenantId(todo.getTenantId());
                    }
                    t1.setTiId(todo.getTiId());
                    t1.setStatus();*/
                    dao.update(Mapper.PTaskTodoMapper, "restoreInvoleSourceTask", todo);
                }
                //return false
                break;
            case PTaskTodo.TYPE_INVOLVED_AFTER:

                break;
            case PTaskTodo.TYPE_CONSIGN:
            case PTaskTodo.TYPE_INVOLVED_SYNC:
                //TODO 计算审批结果
                break;
            case PTaskTodo.TYPE_SKIPPED_NOASSIGNEE:
                completeEngineTask = true;
                break;
            case PTaskTodo.TYPE_SKIPPED_SAMEASSIGNEE:
                completeEngineTask = true;
                break;
            default:
                logger.warn("isCompleteEngineTask default case is invalid.");
        }

        //其他待办
        if (!PTaskTodo.TYPE_SKIPPED_NOASSIGNEE.equals(todo.gettType())
                && !PTaskTodo.TYPE_SKIPPED_SAMEASSIGNEE.equals(todo.gettType())) {
            int count = dao.selectOne(Mapper.PTaskTodoMapper, "countConsignTasks", todo);
            completeEngineTask = count==0;
            if (count>0) {  //检查是否有后加签
                count = dao.selectOne(Mapper.PTaskTodoMapper, "countInvoleAfterTasks", todo);
                if (count>0) {
                    dao.update(Mapper.PTaskTodoMapper, "restoreInvoleAfterTask", todo);
                }
            }
        }

        return completeEngineTask;
    }

    public static PTaskDone todoToDone(PTaskTodo todo) {
        PTaskDone done = new PTaskDone();
        done.setActivityId(todo.getActivityId());
        done.setActivityName(todo.getActivityName());
        done.setCompleteDate(DateUtil.getGMTDate());
        done.setCreateTime(todo.getCreateTime());
        done.setDueTime(todo.getDueTime());
        done.setReceiveTime(todo.getReceiveTime());
        done.setUserId(todo.getUserId());
        done.setUserName(todo.getUserName());
        done.setdUserId(todo.getdUserId());
        done.setdUserName(todo.getdUserName());
        done.setPiEid(todo.getPiEid());
        done.setPiId(todo.getPiId());
        done.setTiId(todo.getTiId());
        done.setTiEId(todo.getTiEId());
        done.setPriority(todo.getPriority());
        done.settType(todo.gettType());
        done.setSummary(todo.getSummary());
        done.setPrevTiid(todo.getPrevTiid());
        return done;
    }

    public static String newId(String colName) {
        String id = null;
        switch (colName.toUpperCase()) {
            case "TI_ID":
                id = "TID-" + UUID.randomUUID();
                break;
            case "PI_ID":
                id = "PID-" + UUID.randomUUID();
                break;
            default:
                id = UUID.randomUUID().toString();
        }
        return id;
    }

}
